package com.quan.TemplateEditor.service;

import com.quan.TemplateEditor.common.R;
import com.quan.TemplateEditor.dao.IAttributeDefDao;
import com.quan.TemplateEditor.dao.IGisTableDao;
import com.quan.TemplateEditor.dto.AtrributeDefSelectorDto;
import com.quan.TemplateEditor.dto.GisTableParams;
import com.quan.TemplateEditor.entity.AttributeDef;
import com.quan.TemplateEditor.entity.GisTable;
import com.quan.TemplateEditor.enums.FeatureType;
import com.quan.TemplateEditor.enums.SpatialRef;
import com.quan.TemplateEditor.interfaces.IdataInterface;
import com.quan.TemplateEditor.params.CodeParams;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.Query;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;

@Service
public class IdataService implements IdataInterface {
    @Autowired
    IGisTableDao gisTableDao;

    @Autowired
    IAttributeDefDao attributeDefDao;

    @PersistenceContext
    private EntityManager entityManager;

    /**
     * 获取图层信息
     * @return
     */
    @Override
    public List<GisTable> getLayer() {
        return gisTableDao.findAll();
    }

    /**
     * 获取图表信息
     * @return
     */
    @Override
    public List<Map<String, Object>> getTableInfo() {
        List<Map<String, Object>> tableInfo = gisTableDao.findTableInfo();
        List<Map<String, Object>> result = new ArrayList<>();
        for(int i=0; i<tableInfo.size(); i++){
            String sql = "select count(*) count from " + tableInfo.get(i).get("name") + ";";
            Query nativeQuery = entityManager.createNativeQuery(sql);
            List<Object> resultList = nativeQuery.getResultList();
            //Object[] objects = resultList.get(0);
            //tableInfo.get(i).put("count", resultList.get(0));
            Map<String,Object> temp = new HashMap<>();
            temp.put("name",tableInfo.get(i).get("name"));
            temp.put("count",resultList.get(0));
            result.add(temp);
        }
        return result;
    }

    /**
     * 通过表名获取表信息
     * @return
     */
    @Override
    public List<Map<String, Object>> getTableInfoByName(String tableName) {
        String sql = "PRAGMA table_info( " +tableName+ ");";
        Query nativeQuery = entityManager.createNativeQuery(sql);
        List<Object[]> resultList = nativeQuery.getResultList();
        List<Map<String, Object>> result = new ArrayList<>();
        for(int i=0; i<resultList.size(); i++){
            Map<String,Object> temp = new HashMap<>();
            temp.put("name",resultList.get(i)[1]);
            temp.put("type", resultList.get(i)[2]);
            temp.put("is_null",resultList.get(i)[3]);
            temp.put("dflt_val",resultList.get(i)[4]);
            result.add(temp);
        }


        return result;
    }

    /**
     * 获取
     * @param tableName
     * @return
     */
    @Override
    public List<AttributeDef> getAttributeByTableName(String tableName) {
        List<AttributeDef> attributeByTableName = attributeDefDao.getAttributeByTableName(tableName);
        return attributeByTableName;
    }

    /**
     *
     * 保存信息
     * @param gisTableParams
     */
    @Override
    public void saveGisTable(GisTableParams gisTableParams) {
        GisTable entity = new GisTable();
        BeanUtils.copyProperties(gisTableParams, entity);
        gisTableDao.save(entity);
    }

    /**
     * 属性功能下拉框选择内容
     * @return
     */
    @Override
    public List<AtrributeDefSelectorDto> getAttributeSelector() {
        List<GisTable>  atrributeDefSelectorList = gisTableDao.getAttributeSelector();
        List<AtrributeDefSelectorDto> res = new ArrayList<>();
        if(atrributeDefSelectorList.size()>0){
            atrributeDefSelectorList.stream().forEach((a)->{
                AtrributeDefSelectorDto atrributeDefSelectorDto=new AtrributeDefSelectorDto();
                atrributeDefSelectorDto.setLayer_name(a.getLayer_name());
                atrributeDefSelectorDto.setAlias_name(a.getAlias_name());
                res.add(atrributeDefSelectorDto);
            });
        }
        return res;
    }

    @Override
    public R getQrCode(CodeParams code) {

        //校验
        R validate = validate(code);
        if(validate.isSuccess()==false){
            return validate;
        }
        //类型不是point，取中点
        String type = code.getGeometry().getType().toUpperCase();
        if(!type.equals(FeatureType.POINT.name())){
            Double[][][] point = GetMinMaxXY(code);
            code.getGeometry().setCoordinates(point);
        }

        //赋码逻辑
        double ilon_sot_degree = 512.0;
        double ilat_sot_degree = 512.0;

        double ilon_sot_minute = 64;
        double ilat_sot_minute = 64;

        double ilon_sot_second = 64;
        double ilat_sot_second = 64;

        double ilon_sot_decimal = 1;
        double ilat_sot_decimal = 1;

        /*double theta0 = 3.1415926 / 180;
        double earth_r = 6378137;*/

        char[][] grid_num_top = {
                {'1', '0'},
                {'3', '2'}
        };
        char[][] grid_num_0 =
        {
            {'2','3'},
            {'0','1'},
        };
        char[][] grid_num_1 =
        {
            {'3','2'},
            {'1','0'},
        };

        char[][] grid_num_2 =
        {
            {'0','1'},
            {'2','3'},
        };

        char[][] grid_num_3 =
        {
            {'1','0'},
            {'3','2'},
        };
        double[][] grid_sot_degree =
        {
            {ilon_sot_degree, ilat_sot_degree},							// 512 0级
            {ilon_sot_degree / 2, ilat_sot_degree / 2},					// 256 1级
            {ilon_sot_degree / 4, ilat_sot_degree / 4},					// 128 2级
            {ilon_sot_degree / 8, ilat_sot_degree / 8},					// 64 3级
            {ilon_sot_degree / 16, ilat_sot_degree / 16},				// 32 4级
            {ilon_sot_degree / 32, ilat_sot_degree / 32},				// 16 5级
            {ilon_sot_degree / 64, ilat_sot_degree / 64},				// 8  6级
            {ilon_sot_degree / 128, ilat_sot_degree / 128},				// 4  7级
            {ilon_sot_degree / 256, ilat_sot_degree / 256},			    // 2  8级
            {ilon_sot_degree / 512, ilat_sot_degree / 512}		        // 1  9级
        };
        double[][] grid_sot_minute =
        {
            {ilon_sot_minute, ilat_sot_minute},							// 64 9级
            {ilon_sot_minute / 2, ilat_sot_minute / 2},					// 32 10级
            {ilon_sot_minute / 4, ilat_sot_minute / 4},					// 16 11级
            {ilon_sot_minute / 8, ilat_sot_minute / 8},					// 8  12级
            {ilon_sot_minute / 16, ilat_sot_minute / 16},				// 4  13级
            {ilon_sot_minute / 32, ilat_sot_minute / 32},				// 2  14级
            {ilon_sot_minute / 64, ilat_sot_minute / 64},				// 1  15级
        };

        double[][] grid_sot_second =
        {
            {ilon_sot_second, ilat_sot_second},							// 64 15级
            {ilon_sot_second / 2, ilat_sot_second / 2},					// 32 16级
            {ilon_sot_second / 4, ilat_sot_second / 4},					// 16 17级
            {ilon_sot_second / 8, ilat_sot_second / 8},					// 8  18级
            {ilon_sot_second / 16, ilat_sot_second / 16},				// 4  19级
            {ilon_sot_second / 32, ilat_sot_second / 32},				// 2  20级
            {ilon_sot_second / 64, ilat_sot_second / 64},				// 1  21级
        };

        double[][] grid_sot_decimal =
        {
            {ilon_sot_decimal, ilat_sot_decimal},				// 1  21级
            {ilon_sot_decimal / 2, ilat_sot_decimal / 2},		// 1/2  22级
            {ilon_sot_decimal / 4, ilat_sot_decimal / 4},		// 1/4  23级
            {ilon_sot_decimal / 8, ilat_sot_decimal / 8},		// 1/8  24级
            {ilon_sot_decimal / 16, ilat_sot_decimal / 16},		// 1/16  25级
            {ilon_sot_decimal / 32, ilat_sot_decimal / 32},		// 1/32  26级
            {ilon_sot_decimal / 64, ilat_sot_decimal / 64},		// 1/64  27级
            {ilon_sot_decimal / 128, ilat_sot_decimal / 128},	// 1/128  28级
            {ilon_sot_decimal / 256, ilat_sot_decimal / 256},	// 1/256  29级
            {ilon_sot_decimal / 512, ilat_sot_decimal / 512},	// 1/512  30级
            {ilon_sot_decimal / 1024, ilat_sot_decimal / 1024},	// 1/1024  31级
            {ilon_sot_decimal / 2048, ilat_sot_decimal / 2048}, // 1/2048  32级
        };




        double x = code.getGeometry().getCoordinates()[0][0][0];
        double y = code.getGeometry().getCoordinates()[0][0][1];
        String temp_qua;
        String hex_str = "";
        String qua_str = "";

        int x_index = 0;
        int y_index = 0;

        if(x > 0){
            x_index = 1;
        }

        if(y < 0){
            y_index = 1;
        }

        qua_str += "G";
        temp_qua = String.valueOf(grid_num_top[y_index][x_index]);
        qua_str += temp_qua;
        hex_str += Integer.toHexString(Integer.parseInt(temp_qua));

        char[][] p_codemap = new char[0][];
        double last_origin_x = 0;
        double last_origin_y = 0;
        if("0".equals(temp_qua)){
            p_codemap = grid_num_0;
            last_origin_x = 0;
            last_origin_y = 0;
        }else if("1".equals(temp_qua)){
            p_codemap = grid_num_1;
            last_origin_x = -256;
            last_origin_y = 0;
        }else if("2".equals(temp_qua)){
            p_codemap = grid_num_2;
            last_origin_x = 0;
            last_origin_y = -256;
        }else if("3".equals(temp_qua)){
            p_codemap = grid_num_3;
            last_origin_x = -256;
            last_origin_y = -256;
        }

        char[] codemap = new char[4];
        int k = 0;
        for (int i = 0; i < p_codemap.length; i++) {
            for (int j = 0; j < p_codemap[i].length; j++) {
                codemap[k++] = p_codemap[i][j];
            }
        }

        double div_x, div_y;
        for (int i = 2; i < 10; i++)
        {
            div_x = last_origin_x + grid_sot_degree[i][0];
            div_y = last_origin_y + grid_sot_degree[i][1];

            if (x > div_x)
            {
                x_index = 1;
                last_origin_x += grid_sot_degree[i][0];
            }
            else
            {
                x_index = 0;
            }

            if (y < div_y)
            {
                y_index = 1;

            }
            else
            {
                y_index = 0;
                last_origin_y += grid_sot_degree[i][1];
            }

            temp_qua = String.valueOf(codemap[y_index*2 + x_index]);
            qua_str += temp_qua;
        }

        double[] pt_minute = new double[2];
        pt_minute[0] = (x - (int) x) * 60;
        pt_minute[1] = (y - (int) y) * 60;
        last_origin_x = 0;
        last_origin_y = 0;
        for (int i = 1; i < 7; i++)
        {
            div_x = last_origin_x + grid_sot_minute[i][0];
            div_y = last_origin_y + grid_sot_minute[i][1];

            if (pt_minute[0] > div_x)
            {
                x_index = 1;
                last_origin_x += grid_sot_minute[i][0];
            }
            else
            {
                x_index = 0;
            }

            if (pt_minute[1] < div_y)
            {
                y_index = 1;

            }
            else
            {
                y_index = 0;
                last_origin_y += grid_sot_minute[i][1];
            }

            temp_qua = String.valueOf(codemap[y_index * 2 + x_index]);
            qua_str += temp_qua;
        }


        double[] pt_second = new double[2];
        pt_second[0] = (pt_minute[0] - (int)pt_minute[0]) * 60;
        pt_second[1] = (pt_minute[1] - (int)pt_minute[1]) * 60;
        last_origin_x = 0;
        last_origin_y = 0;
        for (int i = 1; i < 7; i++)
        {
            div_x = last_origin_x + grid_sot_second[i][0];
            div_y = last_origin_y + grid_sot_second[i][1];

            if (pt_second[0] > div_x)
            {
                x_index = 1;
                last_origin_x += grid_sot_second[i][0];
            }
            else
            {
                x_index = 0;
            }

            if (pt_second[1] < div_y)
            {
                y_index = 1;

            }
            else
            {
                y_index = 0;
                last_origin_y += grid_sot_second[i][1];
            }

            temp_qua = String.valueOf(codemap[y_index * 2 + x_index]);
            qua_str += temp_qua;
        }

        double[] pt_decimal = new double[2];
        pt_decimal[0] = (pt_second[0] - (int)pt_second[0]);
        pt_decimal[1] = (pt_second[1] - (int)pt_second[1]);
        last_origin_x = 0;
        last_origin_y = 0;
        for (int i = 1; i < 12; i++)
        {
            div_x = last_origin_x + grid_sot_decimal[i][0];
            div_y = last_origin_y + grid_sot_decimal[i][1];

            if (pt_decimal[0] > div_x)
            {
                x_index = 1;
                last_origin_x += grid_sot_decimal[i][0];
            }
            else
            {
                x_index = 0;
            }

            if (pt_decimal[1] < div_y)
            {
                y_index = 1;

            }
            else
            {
                y_index = 0;
                last_origin_y += grid_sot_decimal[i][1];
            }

            temp_qua = String.valueOf(codemap[y_index * 2 + x_index]);
            qua_str += temp_qua;

        }
        //double theta = grid_sot_decimal[11][0] * 3.1415926 / (180 * 3600);
        //double n = theta0 / theta * (Math.log((z + earth_r) / earth_r) / Math.log(1 + theta0));
//        String z_str_test = Integer.toString((int) n);
//        String z_str_real = Integer.toBinaryString((int) n);
//        z_str_real = String.format("%32s", z_str_real).replace(' ', '0');

        String qua_code = qua_str;
//        String binary_code_height = z_str_real;
//        String demical_code_height = z_str_test;
        if(StringUtils.isNotBlank(code.getProperties().getFldm())){
            qua_code = code.getProperties().getFldm() + qua_code;
        }

        // 获取当前时间
        LocalDateTime currentTime = LocalDateTime.now();
        // 定义日期时间格式化器
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyyMMddHHmmss");
        // 格式化当前时间为字符串
        String formattedTime = currentTime.format(formatter);

        qua_code = qua_code + formattedTime;


        R r = new R();
        r.setSuccess(true);
        r.setMessage("赋码成功");
        R.Data data = new R.Data();
        data.setIndentity(code.getProperties().getIdentity());
        data.setEntityMatchStatus("100");
        data.setCsm(qua_code);
        r.setData(data);
        return r;
    }

    @Override
    public R validate(CodeParams code) {
        R r = new R();
        R.Data data = new R.Data();
        data.setIndentity(code.getProperties().getIdentity());
        r.setMessage("数据符合规范");
        r.setData(data);
        r.setSuccess(true);
        String type = code.getGeometry().getType().toUpperCase();
        boolean isFeatureType = FeatureType.toMap().containsKey(type);
        if(isFeatureType == false){
            r.setMessage("传入几何类型:"+type+"不符合标准");
            r.setSuccess(false);
            data.setIndentity(code.getProperties().getIdentity());
            data.setEntityMatchStatus("300");
            r.setData(data);
            return r;
        }

        String spatialref = code.getGeometry().getSpatialref();
        boolean isSpatialRef = SpatialRef.toMap().containsKey(spatialref.toUpperCase());
        if(isSpatialRef == false){
            r.setMessage("传入几何坐标系统："+spatialref+"不符合符合标准");
            r.setSuccess(false);
            data.setIndentity(code.getProperties().getIdentity());
            data.setEntityMatchStatus("300");
            r.setData(data);
            return r;
        }

        Double[][][] coordinates = code.getGeometry().getCoordinates();
        if (coordinates.length > 0) {
            for (Double[][] pointArray : coordinates) {
                if (pointArray.length > 0) {
                    for (Double[] point : pointArray) {
                        if (point.length != 2) {
                            //return false; // 每个点应该有两个值（经度和纬度）
                            r.setMessage("参数coordinates不符合GeoJson格式坐标标准");
                            r.setSuccess(false);
                            data.setIndentity(code.getProperties().getIdentity());
                            data.setEntityMatchStatus("300");
                            r.setData(data);
                            return r;
                        }
                    }
                } else {
                    r.setMessage("参数coordinates不符合GeoJson格式坐标标准");
                    r.setSuccess(false);
                    data.setIndentity(code.getProperties().getIdentity());
                    data.setEntityMatchStatus("300");
                    r.setData(data);
                    return r;
                }
            }
            //return true;
        }

        String identity = code.getProperties().getIdentity();
        if(StringUtils.isBlank(identity)){
            r.setMessage("identity唯一标识存在不能为空");
            r.setSuccess(false);
            data.setIndentity(code.getProperties().getIdentity());
            data.setEntityMatchStatus("200");
            r.setData(data);
            return r;
        }

        if(type.equals(FeatureType.POINT.name())){
            if(coordinates.length == 1 && coordinates[0].length != 1){
                r.setMessage("coordinate和属性有效值:"+type+"不一致");
                r.setSuccess(false);
                data.setIndentity(code.getProperties().getIdentity());
                data.setEntityMatchStatus("300");
                r.setData(data);
                return r;
            }
        }else {
            if(coordinates.length == 1 && coordinates[0].length == 1){
                r.setMessage("coordinate和属性有效值:"+type+"不一致");
                r.setSuccess(false);
                data.setIndentity(code.getProperties().getIdentity());
                data.setEntityMatchStatus("300");
                r.setData(data);
                return r;
            }
        }


        String name = code.getProperties().getName();
        if(StringUtils.isBlank(name)){
            r.setMessage("name:实体名称不能为空");
            r.setSuccess(false);
            data.setIndentity(code.getProperties().getIdentity());
            data.setEntityMatchStatus("200");
            r.setData(data);
            return r;
        }
        return r;
    }

    /**
     * 线面取中点
     * @param code
     * @return
     */
    @Override
    public Double[][][] GetMinMaxXY(CodeParams code){
        Double[][][] coordinates = code.getGeometry().getCoordinates();
        double minx = Double.MAX_VALUE;
        double miny = Double.MAX_VALUE;
        double maxx = Double.MIN_VALUE;
        double maxy = Double.MIN_VALUE;

        for(Double[][] polygon : coordinates){
            for(Double[] point : polygon){
                double x = point[0];
                double y = point[1];

                minx = Math.min(minx,x);
                miny = Math.min(miny,y);
                maxx = Math.max(maxx,x);
                maxy = Math.max(maxy,y);
            }
        }
        double pointX = (minx + maxx)/2;
        double pointy = (miny + maxy)/2;
        Double [][][] res = new Double[1][1][2];
        res[0][0][0] = pointX;
        res[0][0][1] = pointy;
        return res;
    }

}
